#include "laurin-80211-station.h"
#include "../laurin-utils.h"


Laurin80211Station::Laurin80211Station(u_int8_t* mac, u_int8_t* bssid)
{
	setMAC(mac);
	setBSSID(bssid);

	_flows_elaborated = false;
	_distance_monitor_ap = -1;
	_distance_from_monitor = -1;
	_distance_from_ap = -1;
}


Laurin80211Station::Laurin80211Station(const Laurin80211Station& station)
{
	setMAC(station._mac);
	setBSSID(station._bssid);

}


Laurin80211Station::~Laurin80211Station()
{
	free(_mac);
	free(_bssid);

	_flows.clear();
}


bool Laurin80211Station::isLocationAvaible()
{
	if((_distance_monitor_ap > 0) && !_flows_elaborated)
		elaborateFlows();

	return _distance_from_monitor >= 0;
}


u_int8_t* Laurin80211Station::getMAC() const
{
	return _mac;
}


u_int8_t* Laurin80211Station::getBSSID() const
{
	return _bssid;
}


void Laurin80211Station::setMAC(u_int8_t* mac)
{
	_mac = (u_int8_t*) malloc(ETH_ALEN);
	memcpy(_mac, mac, ETH_ALEN);
}


void Laurin80211Station::setBSSID(u_int8_t* bssid)
{
	_bssid = (u_int8_t*) malloc(ETH_ALEN);
	memcpy(_bssid, bssid, ETH_ALEN);
}


void Laurin80211Station::addFlow(const Laurin80211Flow& flow)
{
	_flows.push_front(flow);
}


void Laurin80211Station::setDistanceBetweenMonitorAndAP(double distance)
{
	_distance_monitor_ap = distance;
	elaborateFlows();
}


double Laurin80211Station::getDistanceFromAP() const
{
	return _distance_from_ap;
}


double Laurin80211Station::getDistanceFromMonitor() const
{
	return _distance_from_monitor;
}


void Laurin80211Station::elaborateFlows()
{

	_flows_elaborated = false;

	std::list<Laurin80211Flow>::iterator b = _flows.begin();
	std::list<Laurin80211Flow>::iterator e = _flows.end();

	double a = 0;		// tof_am + tof_ab where a is the station, b the access point, and m this station
	double c = 0;		// tof_ab - tof_am
	double aux;
	int count_a = 0;
	int count_c = 0;


	while(b != e)
	{

		if(b->direction == Laurin80211Flow::FROM_AP_TO_STATION)
		{
			a +=  b->ack_tsft - b->data_tsft - b->sifs_time - b->data_duration + (_distance_monitor_ap / SPEED_OF_LIGHT);
			count_a++;
		}
		else
		{
			c += b->ack_tsft - b->data_tsft - b->sifs_time - b->data_duration - (_distance_monitor_ap / SPEED_OF_LIGHT);
			count_c++;
		}

		b++;
	}

	_flows_elaborated = true;

	if(count_c == 0 || count_a == 0)
	{
		_distance_from_monitor = -1;
		_distance_from_ap = -1;
		return;
	}

	a /= count_a;
	c /= count_c;


	double tmp = (a - c) / 2.0;
	_distance_from_ap = tmp * SPEED_OF_LIGHT;
	_distance_from_monitor = (c - tmp) * SPEED_OF_LIGHT;
}
